package com.wry.api.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wry.api.SpikeService;
import com.wry.entity.Goods;
import com.wry.entity.Order;
import com.wry.enums.OrderStatusEnum;
import com.wry.enums.TopicEnum;
import com.wry.service.GoodsService;
import com.wry.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Service
@Slf4j
public class SpikeServiceImpl implements SpikeService {

    @Resource
    private GoodsService goodsService;
    @Resource
    private OrderService orderService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Resource
    private RocketMQTemplate rocketMQTemplate;
    @Resource
    private RedissonClient redissonClient;

    private static final String GOODS_HASH = "goods:stock";

    private static final String LOCK_KEY = "RESOURCE_KEY";

    @Override
    public String spike(Long goodsId) {
        //定义锁
        final RLock lock = redissonClient.getLock(LOCK_KEY);
        try {
            // 尝试加锁，最大等待时间500ms，上锁50ms自动解锁
            if (lock.tryLock(500, 50, TimeUnit.MILLISECONDS)) {
                Object obj = redisTemplate.opsForHash().get(GOODS_HASH, String.valueOf(goodsId));
                if (Objects.isNull(obj)) {
                    return "商品不见了~";
                }
                Goods goods = JSONObject.parseObject(obj.toString(), Goods.class);
                log.info("当前缓存中库存：{}", goods.getNum());
                if (Objects.isNull(goods) || goods.getNum() <= 0) {
                    return "库存不足";
                }
                log.info("---------------start------------");
                //扣减redis中库存
                Integer num = goods.getNum();
                goods.setNum(--num);
                redisTemplate.opsForHash().put(GOODS_HASH, String.valueOf(goods.getId()), JSON.toJSONString(goods));
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 释放锁
            lock.unlock();
        }
        //生成一条订单
        Long orderId = System.currentTimeMillis();
        rocketMQTemplate.convertAndSend(TopicEnum.ORDER_CREATE_TOPIC.name(),orderId+"_"+goodsId);
        // 发送延时消息 检查订单状态
        // 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h"; 1--->18
        Message<String> message = MessageBuilder.withPayload(String.valueOf(orderId)).build();
        // 3min中内支付，未支付将取消订单
        rocketMQTemplate.syncSend(TopicEnum.ORDER_CHECK_TOPIC.name(), message,2000,7);
        return "抢到了！请3min内完成支付";
    }

    @Override
    public void sync() {
        List<Goods> goodsList = goodsService.list();
        goodsList.forEach(goods ->{
            redisTemplate.opsForHash().put(GOODS_HASH,String.valueOf(goods.getId()),JSON.toJSONString(goods));
        });
        log.info("stock sync ok");
    }

    @Override
    public String pay(Long orderId) {
        final Order order = orderService.lambdaQuery()
                .eq(Order::getOrderId, String.valueOf(orderId))
                .one();
        if (Objects.isNull(order)){
           return orderId+"：订单不存在！";
        }
        if (OrderStatusEnum.CANCEL.name().equals(order.getStatus())){
            return "订单已经取消！";
        }
        if (OrderStatusEnum.SUCCESS.name().equals(order.getStatus())){
            return "你已经付过钱了！";
        }
        try {
            // 发送异步消息处理订单的付款
            rocketMQTemplate.asyncSend(TopicEnum.ORDER_PAY_TOPIC.name(), String.valueOf(orderId), new SendCallback() {
                @Override
                public void onSuccess(SendResult sendResult) {
                    log.info("成功发送...");
                }
                @Override
                public void onException(Throwable throwable) {
                    log.error("发送失败...");
                }
            });
        }catch (Throwable throwable){
            throwable.printStackTrace();
            return "支付失败，系统异常...";
        }
        final Goods goods = goodsService.getById(order.getGoodsId());
        return "支付成功...【"+goods.getName()+"】 * 1";
    }
}
